# Spec: BrainDrive Budgeting (Finance Project Page V1)

> **Save to:** `BrainDrive-Library/projects/active/braindrive-budgeting/spec.md`
> Generated from `/interview` + `/landscape` + `/feature-spec` on 2026-05-13
> **Status:** V1 spec. Source decisions: [[decisions.md]] D1–D21. Landscape: [[landscape.md]].

---

## Overview

### What We're Building

Budgeting on the **BrainDrive Finance project page** — the first owner-facing feature built on top of the [[document-processing]] substrate. Dave W (V1 dogfood) uploads **bank and credit card statements** through doc processing, stores a budget on the Finance page, and asks BrainDrive *"how am I doing?"* — BrainDrive reads the parsed transactions + the budget, compares them, and advises **conversationally + via a generated breakdown report**. Goal is to **replace the standalone budgeting apps** Dave W (and eventually owners) would otherwise use (Mint successors, YNAB, Copilot, Monarch, Rocket Money, etc.).

**Paradigm: category-tracking, not zero-based or envelope.** [[D6]] (`category | monthly_limit | notes` budget table) places BrainDrive alongside Monarch / Copilot / Simplifi / Empower / PocketGuard. Owners migrating from YNAB or EveryDollar (zero-based) or Goodbudget (envelope) will find this foreign — flagged explicitly. Worldview-bound users are deferred to V2+.

### Target User

- **Persona:** Owner — V1 is Dave W only ([[D3]]); V1.1+ targets Adam Carter range (technically comfortable owners) per braindrive-repo D184; full Katie audience deferred.
- **Technical Level:** V1 — comfortable opening markdown files, editing tables, working in chat. V1.1+ raises the floor.
- **Context:** Owner downloads statements from their bank a few times a month, drops them into BrainDrive, and treats the Finance project page as the single place to check spending and ask budget questions. Replaces 4–5 standalone apps over time ([[D4]] unification pillar).

### Problem Statement

BrainDrive already holds the owner's context (goals, values, life situation). The [[document-processing]] substrate can get **bank and credit card statements** into BrainDrive memory. **The gap is the feature on the Finance page** that turns parsed transactions + a stored budget into actionable advice: budget storage shape, comparison logic, conversational surface, drill-down, edit/correct affordances. Without this, the substrate produces parsed data with no consumer; BrainDrive can't answer *"how am I doing?"* and owners still need to run a separate budgeting app.

Three load-bearing differentiator pillars over Mint/YNAB/Copilot/Monarch/Rocket Money ([[D4]]):

1. **Knows-you advice** — Claude already knows the owner's goals + context; advice is grounded in *who they are*, not just transaction patterns.
2. **Unification** — replaces 4–5 standalone apps.
3. **Data ownership / no-Plaid privacy** — files stay on the owner's BrainDrive instance. No third-party transaction aggregator. Credible wedge given the 2025–2026 Plaid backlash (60% of top apps share data per Incogni; $58M Plaid settlement).

---

## User Stories

> All V1 user stories are **Confirmed** by [[decisions.md]] D1–D21 unless noted. Status field is included for agents.

### US-1: Conversational budget setup, triggered from Finance project interview — **Confirmed** ([[D8]], amended 2026-05-13)

As an owner who has indicated through the Finance project interview that I want help tracking spending, I want BrainDrive to walk me through setting up my budget conversationally, so that I don't need to learn a form or template.

<details>
<summary>Details — source, steps, acceptance criteria</summary>

**Source:** [[D8]] (day-1 setup, amended 2026-05-13 — see Trigger below), [[D6]] (budget storage), [[D7]] (categories hybrid).

**Trigger (amended 2026-05-13):** Budget setup is **not** auto-triggered on first Finance project page navigation. The Finance project page runs its own broader interview (e.g., "what would you like BrainDrive to help with regarding your finances? — tracking spending, net worth, tax prep, debt payoff, …"); budget setup kicks off **only if** the interview surfaces budgeting intent (e.g., owner picks "tracking spending" or "I want a budget"). Owner can also kick off budget setup explicitly later via chat ("set up a budget"). The Finance project interview itself is **out of scope** for this project — it's a braindrive-repo / Finance-project-page concern; see Open Questions ([[Q12]]).

**Steps (after trigger):**
1. Trigger event: Finance project interview returns "owner wants budgeting" OR owner asks for it in chat.
2. BrainDrive checks `finance/budget.md`; if it exists, asks before overwriting.
3. BrainDrive opens a conversation: *"Let's set up your budget — what categories matter to you?"*
4. Owner names categories conversationally (e.g., "groceries, eating out, transport, subscriptions, fun").
5. BrainDrive asks for monthly limits per category.
6. BrainDrive writes `finance/budget.md` with the resulting markdown table.
7. BrainDrive prompts: *"Ready to upload your first statement?"* and links/triggers the [[document-processing]] upload flow.

**Acceptance Criteria (Given-When-Then):**

```gherkin
Given the Finance project interview returns budgeting-intent OR the owner explicitly asks to set up a budget
When the budget-setup trigger fires
Then BrainDrive starts the conversational setup flow
And asks for categories and monthly limits
And writes finance/budget.md when the owner confirms
And prompts for first statement upload
```

```gherkin
Given the owner navigates to the Finance project page for the first time
When the Finance project interview runs
Then BrainDrive does NOT auto-create a budget
And does NOT assume the owner wants budgeting
And only triggers budget setup if the interview surfaces that intent
```

```gherkin
Given finance/budget.md already exists
When budget setup is triggered again (explicitly by owner)
Then BrainDrive offers to update, replace, or cancel
And does NOT silently overwrite
```

**Status:** Confirmed (trigger flow amended 2026-05-13 — interview-driven, not navigation-driven)

</details>

### US-2: Upload a bank or credit card statement and get a proactive summary — **Confirmed** ([[D9]], [[D21]], [[D22]])

As an owner, I want BrainDrive to summarize what it parsed right after my statement upload (bank or credit card), so that I have immediate situational awareness without asking.

<details>
<summary>Details — source, steps, acceptance criteria</summary>

**Source:** [[D9]] (proactive summary), [[D21]] (subscription detection at parse), [[D22]] (scope includes bank + credit card; transfer classification at parse), cross-project to [[document-processing]] D22/D26 (substrate parsing).

**Steps:**
1. Owner triggers upload of a bank or credit card statement via the Finance project page (existing BrainDrive file-upload UI — pending [[Q7]] / doc-processing Q14).
2. Substrate parses the statement via Haiku 4.5 ([[document-processing]] D22) and writes `finance/statements/YYYY-MM-source.md` ([[D12]]) with per-transaction `recurring` flag ([[D21]]) AND per-transaction `type` field (`expense | income | transfer | refund | fee`, per [[D22]]).
3. Substrate signals "parse complete" to the budgeting consumer.
4. BrainDrive opens chat: *"I parsed your Capital One statement — 87 transactions, $3,410 in expenses (excluding $1,200 transfer payment). Eating out at 92% of budget. Looks like 4 transactions may be recurring: [list]. Want to see the breakdown?"*
5. BrainDrive flags any uncertain categorizations OR uncertain `type` classifications (especially credit-card payments and refunds) and asks for confirmation inline.

**Acceptance Criteria (Given-When-Then):**

```gherkin
Given the owner has a budget.md and uploads a parseable bank or credit card statement
When the substrate finishes parsing
Then BrainDrive surfaces a proactive chat summary
And the summary includes: transaction count, expense total (excluding transfers/income/refunds), top over-budget category, recurring-flag count
And BrainDrive offers to show the breakdown report
```

```gherkin
Given a credit card statement contains a payment from the owner's bank account
When the substrate classifies the inflow as type=transfer (per D22)
Then BrainDrive surfaces the transfer total separately in the summary ("$1,200 transfer payment")
And the transfer is NOT counted against any budget category
And the transfer is NOT counted as income
```

```gherkin
Given the substrate parse fails or the statement is corrupt
When the upload returns an error from the substrate
Then BrainDrive surfaces the error conversationally
And does NOT write a partial statement file
And does NOT update the breakdown report
```

**Status:** Confirmed

</details>

### US-3: Ask "how am I doing this month?" — **Confirmed** ([[D10]])

As an owner, I want to ask BrainDrive *"how am I doing this month?"* in chat and get a useful, opinionated answer with a link to the full breakdown.

<details>
<summary>Details — source, steps, acceptance criteria</summary>

**Source:** [[D10]] (Q&A shape), [[D4]] pillar #1 (knows-you advice grounding).

**Steps:**
1. Owner asks in chat: *"how am I doing this month?"* or similar.
2. BrainDrive reads `finance/budget.md`, all in-month statement files in `finance/statements/`, and `finance/rules.md`.
3. BrainDrive aggregates spend per category (sum-per-category invariant from [[D18]]).
4. BrainDrive returns a short conversational summary + path to the breakdown report: *"You're over on eating out by $80, under on transport by $50, on track overall. Full breakdown at finance/reports/latest.md."*

**Acceptance Criteria (Given-When-Then):**

```gherkin
Given the owner has a budget.md and at least one parsed statement for the current month
When the owner asks "how am I doing this month?"
Then BrainDrive returns a conversational summary
And the summary names the largest over-budget category (if any) and the largest under-budget category
And the summary links to finance/reports/latest.md
And the numbers in the summary match the breakdown report exactly
```

```gherkin
Given no statements exist for the current month
When the owner asks "how am I doing this month?"
Then BrainDrive responds that no statements have been uploaded yet for this month
And offers to walk through an upload
```

**Status:** Confirmed

</details>

### US-4: Drill down into a category — **Confirmed** (amended [[D16]])

As an owner, I want to ask *"what's in groceries?"* and get the full list of transactions in that category, so I can see where the spend went.

<details>
<summary>Details — source, steps, acceptance criteria</summary>

**Source:** Amended [[D16]] (full-ledger drill-down allowed conversationally), `/landscape` §5.1 #2 (drill-down gap).

**Steps:**
1. Owner asks: *"what's in groceries?"* (or similar phrasing).
2. BrainDrive reads all in-month statement files; filters transactions classified as Groceries (per [[D7]] categorization + accumulated rules per [[D11]]/[[D17]]).
3. BrainDrive returns the full transaction list for that category in chat, with merchant + amount + date.

**Acceptance Criteria (Given-When-Then):**

```gherkin
Given there are transactions classified to the requested category in the current month
When the owner asks "what's in [category]?"
Then BrainDrive returns the full list of those transactions inline
And each line shows: date, merchant, amount
And the listed amounts sum to the category's "spent" total in the breakdown report
```

```gherkin
Given the requested category has zero transactions in the current month
When the owner asks "what's in [category]?"
Then BrainDrive responds that no transactions are classified there
And offers to show what categories DO have spend
```

**Status:** Confirmed

</details>

### US-5: Correct a miscategorized transaction and accumulate a rule — **Confirmed** ([[D11]], [[D17]])

As an owner, I want to fix a miscategorization conversationally and have BrainDrive offer to learn the pattern, so I don't have to repeat the correction.

<details>
<summary>Details — source, steps, acceptance criteria</summary>

**Source:** [[D11]] (conversational + rules accumulate), [[D17]] (rules file format).

**Steps:**
1. Owner says: *"That Amazon charge was groceries, not shopping."*
2. BrainDrive identifies the transaction in question (most recent matching Amazon charge, or owner-specified).
3. BrainDrive updates the transaction's category in `finance/statements/<file>.md`.
4. BrainDrive recomputes the breakdown report.
5. BrainDrive asks: *"Want me to categorize future Amazon charges as Groceries by default?"*
6. If owner says yes, BrainDrive appends `Amazon | Groceries | <note>` to `finance/rules.md`.

**Acceptance Criteria (Given-When-Then):**

```gherkin
Given a parsed statement contains an Amazon transaction categorized as Shopping
When the owner says "that Amazon charge was groceries, not shopping"
Then BrainDrive updates the transaction's category in its statement file
And recomputes the breakdown report
And offers to add a rule for future Amazon charges
```

```gherkin
Given the owner accepts the rule offer
When BrainDrive writes to finance/rules.md
Then the rule is appended as a new row in the Pattern | Category | Notes table
And future categorization on new uploads applies the rule
```

```gherkin
Given a rule "Amazon → Groceries" already exists
When a new statement contains an Amazon charge
Then it is categorized as Groceries at parse time
And does NOT trigger the categorization-confirm prompt
```

**Status:** Confirmed

</details>

### US-6: View the breakdown report — **Confirmed** ([[D5]], [[D16]])

As an owner, I want a generated breakdown report I can open and see my budget vs. actual at a glance.

<details>
<summary>Details — source, steps, acceptance criteria</summary>

**Source:** [[D5]] (markdown V1; HTML investigation in V1), [[D16]] (category table only in static report), [[D2]] (replace-budgeting-apps framing).

**Steps:**
1. Breakdown report is written to `finance/reports/breakdown-YYYY-MM.md` (and `.html` if Q7 / [[D5]] HTML feasibility lands during V1).
2. `finance/reports/latest.md` (+ `.html`) is a pointer kept current.
3. Report regenerates after any statement upload, rule change, or correction.

**Static report content (V1 — [[D16]]):**
- Per-category table: `category | budget | spent | remaining | % used | status (over/under)`.
- No summary header, no top transactions, no full ledger (all deferred to V1.1+ per [[D16]] amended).
- Markdown V1 guaranteed; HTML V1 if Dave J can render it (Q7).

**Acceptance Criteria (Given-When-Then):**

```gherkin
Given the owner has a budget and at least one in-month statement
When BrainDrive generates or refreshes the breakdown report
Then finance/reports/breakdown-YYYY-MM.md exists
And finance/reports/latest.md points to (or is a copy of) the current month's report
And the report contains exactly the category table from D16 — no extra sections
And the report's "spent" totals satisfy the sum-per-category invariant (D18)
```

```gherkin
Given Q7 is resolved positive (HTML rendering works)
When BrainDrive generates the breakdown report
Then finance/reports/breakdown-YYYY-MM.html also exists alongside the .md
And both render the same data
```

**Status:** Confirmed (markdown V1); HTML conditional on Q7 / [[Q7]].

</details>

### US-7: Detect and handle a duplicate statement upload — **Confirmed** ([[D13]])

As an owner, I want BrainDrive to notice when I'm re-uploading a statement I've already given it, so I don't accidentally double-count.

<details>
<summary>Details — source, steps, acceptance criteria</summary>

**Source:** [[D13]] (detect + ask), Q11 (dedup mechanism — Dave J resolves during V1 build).

**Steps:**
1. Owner uploads a statement.
2. Substrate parses; budgeting consumer reads the metadata (source account + date range — likely Haiku-extracted per Q11).
3. Consumer compares to existing files in `finance/statements/`.
4. On suspected duplicate, BrainDrive prompts: *"Looks like the same statement — replace, merge, or skip?"*
5. Owner picks; consumer acts (replace overwrites; merge folds non-duplicate transactions; skip discards new parse).

**Acceptance Criteria (Given-When-Then):**

```gherkin
Given a parsed statement matches the (source, date-range) of an existing finance/statements/ file
When the substrate completes parsing
Then BrainDrive prompts the owner: replace / merge / skip
And does NOT silently overwrite or append
And does NOT auto-decide
```

```gherkin
Given the owner chooses "replace"
When BrainDrive applies it
Then the existing statement file is overwritten with the new parse
And the breakdown report regenerates
```

**Status:** Confirmed (detection signal pending Q11)

</details>

### US-8: Edit the budget directly — **Confirmed** ([[D6]])

As an owner, I want to edit `finance/budget.md` directly (or conversationally) when my targets change, without re-running setup.

<details>
<summary>Details — source, steps, acceptance criteria</summary>

**Source:** [[D6]] (budget storage), [[D4]] pillar #3 (owner can hand-edit files).

**Steps:**
1. Owner edits `finance/budget.md` directly (any markdown editor) OR asks in chat: *"raise eating out to $500."*
2. If conversational, BrainDrive writes the change to `finance/budget.md`.
3. The breakdown report regenerates on next refresh.

**Acceptance Criteria (Given-When-Then):**

```gherkin
Given the owner edits finance/budget.md (manually or via chat)
When the next breakdown report is generated
Then it reflects the new limits
And the sum-per-category invariant still holds for actual spend
```

```gherkin
Given the owner removes a category from finance/budget.md mid-month
When transactions classified to that category exist in the in-month statements
Then BrainDrive surfaces the orphaned spend conversationally
And asks how to handle it (re-categorize / leave as un-budgeted)
```

**Status:** Confirmed

</details>

---

## Invariants & Edge Cases

### Properties That Must Always Hold

These drive property-based tests. Stated as universal claims, not example assertions.

- [ ] **Sum-per-category invariant ([[D18]]) — foundational:** For every category in any breakdown report: `report.categories[X].spent == sum(transactions where transaction.category == X and transaction.type == 'expense' and transaction.date is in report.month)`. Restricted to expense-typed transactions per [[D22]]. If they disagree, the report is wrong by definition.
- [ ] **Substrate alignment:** Each statement upload (bank or credit card) produces exactly one `finance/statements/YYYY-MM-source.md` file ([[D12]], [[D22]]). One upload, one memory file. No partial writes on parse failure (US-2).
- [ ] **Date filter respects transaction date, not statement date ([[D14]]):** A transaction dated 2026-04-30 in a statement covering 4/15–5/15 belongs to the April report, not May, regardless of which statement file holds it.
- [ ] **Type filter ([[D20]] + [[D22]]):** The breakdown report's "spent" totals include ONLY transactions with `type == expense`. `income`, `transfer`, `refund`, and `fee` are excluded from budget comparison. Recurring/one-off classification ([[D21]]) is orthogonal — an `income` transaction can be recurring; an `expense` can be one-off.
- [ ] **Transfer symmetry ([[D22]]):** When the same transfer appears in both a bank statement (outflow) and a credit card statement (inflow), neither side counts against budget. Naive aggregation would either inflate expenses or surface phantom income; the `type == transfer` classification prevents both.
- [ ] **Rules persist across re-parses ([[D11]], [[D17]]):** A row in `finance/rules.md` applies to all future categorizations, including re-parses of existing statement files.
- [ ] **Reports are derived, statements are source-of-truth:** Deleting `finance/reports/breakdown-2026-05.md` and regenerating it from the same statements + budget + rules yields a byte-identical (modulo timestamps) report.

### Edge Cases to Test

- [ ] **Empty statement** (statement file with zero transactions): report shows $0 spent, no errors, summary message clear.
- [ ] **Statement with only deposits/transfers/payments**: report shows $0 spent ([[D20]] + [[D22]] exclusion); summary mentions transfer/income totals separately for visibility but they don't count against budget.
- [ ] **Credit card statement with only a payment (no charges)**: report shows $0 spent; summary mentions the payment as `type=transfer`; no phantom income.
- [ ] **Credit card payment from bank statement → credit card statement**: both sides classified `type=transfer` by substrate ([[D22]]); both excluded from budget; surfaced separately in summary.
- [ ] **Refund on a credit card** (positive amount, refunded purchase): substrate classifies `type=refund`; excluded from budget; surfaced separately. Owner can override via [[D11]] correction flow if the refund should reduce the category's spent total (V1 design: refunds don't reduce spent; revisit in V1.1).
- [ ] **Statement spans two months** (BoA 4/15–5/15, or credit card cycle 4/20–5/19): May report includes May-dated transactions only; April report includes April-dated only.
- [ ] **Statement parse fails entirely** (substrate returns error): no statement file written; breakdown report unchanged; owner sees error in chat (US-2 AC).
- [ ] **Statement partially parsed** (substrate D17 sum invariant fails on substrate side): substrate is responsible for not landing a partial file; budgeting consumer trusts substrate. Cross-project test, not a budgeting-layer test.
- [ ] **Owner removes a category from budget.md mid-month**: report shows the category's spend as "un-budgeted" or surfaces it conversationally (US-8 AC).
- [ ] **Owner adds a category to budget.md mid-month**: report includes the new category at $0 spent (no historical re-categorization triggered).
- [ ] **Duplicate upload** (same source + date range): detected; owner prompted (US-7).
- [ ] **Rule conflict** (owner adds two rules that match the same pattern): last-write-wins on the file; rules table read top-to-bottom; first match wins on application. Document explicitly.
- [ ] **Statement in foreign currency / unusual format**: substrate concern; budgeting layer trusts substrate output.
- [ ] **Transaction with category not in budget.md**: report shows it as "un-budgeted" line at bottom of category table; surfaces conversationally on next Q&A.
- [ ] **Owner asks "how am I doing this month?" on the 1st** (no in-month statements yet): respond with "no statements uploaded for this month yet" (US-3 AC).
- [ ] **Owner asks about a category with zero transactions**: respond "no transactions classified there" + offer alternatives (US-4 AC).
- [ ] **Owner navigates to Finance project page for the first time**: Finance project interview runs (not in this project's scope per Q12); budget setup does NOT auto-trigger ([[D8]] amended). US-1.

### Failure Modes

| Scenario | Expected Behavior |
|----------|-------------------|
| Substrate parse fails | Error surfaced in chat (US-2); no statement file written; report unchanged. |
| Substrate mis-classifies a transaction's `type` (e.g., transfer flagged as expense) | Owner uses correction flow ([[D11]]) — "that was a credit card payment, not an expense" → BrainDrive updates the statement file's type field AND offers to add a type-rule (recurring transfers between specific accounts). |
| `finance/budget.md` is malformed (bad table) | BrainDrive surfaces parse error conversationally; offers to fix or re-run setup. Reports are NOT generated until budget.md is valid. |
| `finance/rules.md` malformed | BrainDrive surfaces error; falls back to LLM categorization without rules until owner fixes. |
| Q7 (HTML rendering) returns negative late in V1 | V1 ships markdown-only reports per [[D5]] fallback; no V1 functional blocker. |
| Q11 (dedup detection mechanism) returns negative | Fall back to filename + owner-confirmation; document gap. |
| Q12 (Finance project interview not built yet) | V1 falls back to "owner asks for budget in chat" as the only trigger. No auto-creation. |
| Owner deletes `finance/statements/<file>.md` manually | Next report refresh excludes that statement's data; no error. Reports are derived from current state of statements/. |
| Conflicting rules in rules.md | First match wins (top-down); document the precedence rule in rules.md header. |

---

## Detailed Requirements

### Core Functionality
- [ ] Conversational setup flow for first-run when `finance/budget.md` does not exist ([[D8]]).
- [ ] Budget storage at `finance/budget.md` with `category | monthly_limit | notes` table ([[D6]]).
- [ ] Read-and-aggregate logic: load all in-month statement files + budget + rules → compute per-category totals.
- [ ] Categorization application: substrate output + accumulated rules from `finance/rules.md` ([[D17]]).
- [ ] Breakdown report generation at `finance/reports/breakdown-YYYY-MM.{md, html?}` + `latest.{md, html?}` pointer ([[D5]], [[D16]]).
- [ ] Sum-per-category invariant ([[D18]]) — implemented as both a runtime guard and a property test.
- [ ] Post-upload proactive summary in chat ([[D9]]) — includes spend total, top over-budget category, recurring-flag count from [[D21]].
- [ ] Conversational Q&A handler for "how am I doing?" and category drill-down ([[D10]], amended [[D16]]).
- [ ] Conversational correction flow + rule-acceptance prompt ([[D11]]).
- [ ] Duplicate upload detection + owner prompt ([[D13]]).
- [ ] Date-based aggregation (transactions filtered by transaction date, not statement date) ([[D14]]).
- [ ] Recurring/one-off classification surfacing in post-upload summary and on conversational request ([[D21]]).

### User Interface
- [ ] All interaction happens through BrainDrive's existing chat UI + file system. No new UI components.
- [ ] The Finance project page surfaces (per BrainDrive's existing project-page model): the budget.md, statements/ folder, rules.md, and reports/ folder. Exact rendering shape is upstream ([[Q6]] / braindrive-repo).
- [ ] Owner opens reports in their preferred markdown viewer (V1 markdown). HTML reports open in browser if Q7 lands.

### Data & State
- [ ] `finance/budget.md` — owner-edited; markdown table.
- [ ] `finance/statements/YYYY-MM-source.md` — substrate-written; one per upload ([[D12]]).
- [ ] `finance/rules.md` — markdown table; mixed-author (owner edits + chat-driven appends).
- [ ] `finance/reports/breakdown-YYYY-MM.{md, html?}` — BrainDrive-generated; never owner-edited. Treated as derived data.
- [ ] `finance/reports/latest.{md, html?}` — pointer (file or copy) to current month's report.

---

## Scope

### Feature Type
- [x] **Production** (V1 MVP, owner-facing dogfood). Real owner relies on this for financial decisions; no skipped error handling or partial state on failure.

### Implementation Location
- [x] **Core Modification (light)** — BrainDrive's Finance project page conversational handlers + file-watcher logic need to know about budgeting concepts (budget.md, rules.md, report regeneration triggers, post-upload summary content).
- [ ] Plugin — not a fit; budgeting is a first-class BrainDrive feature on the Finance project page, not a sidecar.

**Justification for Core:** Budgeting is the first owner-facing feature built on top of [[document-processing]]. It establishes the pattern for *all* future feature projects on top of the substrate (transcripts → personal context, health docs → wellness advisor, etc.). It also requires substrate prompt extensions ([[D21]] recurring detection) that aren't pluggable. **Scope of core changes:**
- Finance project page conversational handlers (setup, Q&A, drill-down, correction).
- Post-upload trigger from substrate → budgeting consumer (signal that parsing completed).
- Report generator (probably an LLM-driven file-rewrite of `finance/reports/...` from current statement + budget + rules state).
- Haiku parsing prompt extension in substrate ([[document-processing]] D22) to add `recurring` field — cross-project ask.

---

## MVP Scope (v1)

### Included (Confirmed via D1–D22)
- US-1 conversational budget setup, **triggered by Finance project interview output OR explicit owner ask** ([[D8]] amended). Auto-trigger on Finance page entry is **removed**.
- US-2 statement upload (bank OR credit card) + proactive summary + recurring-flag surfacing + transfer-classification surfacing ([[D9]], [[D21]], [[D22]])
- US-3 conversational Q&A ([[D10]])
- US-4 conversational drill-down full-ledger ([[D16]] amended)
- US-5 conversational correction + rule accumulation ([[D11]], [[D17]])
- US-6 markdown breakdown report ([[D5]], [[D16]]); HTML if Q7 lands
- US-7 duplicate upload detection ([[D13]])
- US-8 direct budget editing ([[D6]])
- Single-month scope ([[D2]])
- All-accounts-combined: bank + credit cards in one budget ([[D19]], [[D22]])
- Expenses-only via `type` field; transfers, income, refunds, fees excluded from budget ([[D20]], [[D22]])
- Sum-per-category invariant ([[D18]]) — restricted to `type == expense` per [[D22]]
- Category-tracking paradigm explicitly named (Q-L4 spec resolution).
- Data-ownership pillar explicitly stated ([[D4]] strengthened, Q-L5 spec resolution).

### Explicitly Excluded (v1)

| Item | Why | Where it goes |
|------|-----|---------------|
| Plaid / Finicity / MX / any bank-sync | Erodes [[D4]] data-ownership pillar — anti-differentiator | **Never** (deliberate exclusion) |
| Mobile-native budgeting app | BrainDrive's React chat client is the surface | **Never** |
| Bill negotiation services | Requires service organization | **Never** |
| In-app subscription cancellation | Requires partnerships | **Never**; detection (D21) yes |
| Credit-score monitoring | Third-party integration violates pillar #3 | **Never or external connector V2+** |
| Zero-based / envelope mode | Paradigm mismatch ([[D6]] is category-tracking) | V2+ if audience demand; Q-L6 |
| Multi-month / month-over-month trends | Single-month V1 ([[D2]]) | V1.1+ — first stretch beyond V1 |
| Net worth / income / cash flow tracking | Expense-only V1 ([[D20]]) | V1.1+ — paired with income |
| Mid-month proactive nudges | Single proactive moment in V1 (post-upload, D9) | V1.1+ ([[Q2]]/[[Q8]]) |
| Summary header in report (totals, days remaining) | Narrower static report ([[D16]]) | V1.1+ |
| Top transactions per category in static report | Conversational drill-down covers it ([[D16]] amended) | V1.1+ if static is wanted |
| Adaptive budget suggestions | "Last 3 months you averaged $X, consider..." needs history | V1.1+ |
| Per-account breakdown | Single-budget V1 ([[D19]]) | V1.1+ |
| Worldview accommodation (envelope/zero-based) | Audience deferred (Q-L6) | V2+ |

---

## Future Versions

### V1.1 (likely the next push, post-V1 dogfood)

In rough priority order from `/landscape` §6.2:

1. **Month-over-month + 3-month trend** — natural extension on top of [[D12]] one-file-per-statement.
2. **Transaction drill-down in the static report** (the full ledger; lift from [[D16]] amended state).
3. **Income / cash-flow tracking** — lift [[D20]]'s expense-only restriction. Enables "am I saving?".
4. **Mid-month proactive nudges** — threshold-based; runs at chat-load time.
5. **Adaptive budget suggestions** — Copilot's Adaptive Budgets + EveryDollar's Margin Finder paradigm.
6. **Net worth (read-only)** — `finance/accounts.md` with manual balances.
7. **HTML report rendering** — if Q7 hasn't already landed in V1.
8. **Goals / savings tracking** — `finance/goals.md`.

### V2+ (longer-term)
- Worldview support: envelope / zero-based modes for YNAB/EveryDollar/Goodbudget migrators (Q-L6).
- Cross-context queries ("did my spending spike correlate with a stressful week in my work project?") — cross-substrate consumer feature.
- Connector substrate alongside doc-processing for owners who DO opt into auto-pull from sources (still owner-instance-side, not Plaid).

### Future Consideration
- Cross-doc reasoning: budgeting reads transcripts to flag emotionally-loaded purchases.
- Tax categorization assist.
- Joint / shared finances (multi-owner Memory).

---

## Technical Context

### Integration Points
- [x] **[[document-processing]] substrate** — Hard upstream dependency. Reads parsed statement files; relies on D21 substrate-prompt extension for recurring tags. Cross-project ask: Dave J's T-571 V1 prototype includes the `recurring` field per [[D21]].
- [x] **BrainDrive's existing chat handler** — registers Finance-page intent handlers (setup, Q&A, drill-down, correction, budget edits).
- [x] **BrainDrive's file system / Memory** — all data lives as markdown files in the owner's BrainDrive memory; no separate database.
- [x] **BrainDrive Model (Haiku 4.5)** — used for substrate parsing AND for report generation / Q&A. Same routing as [[doc-processing]] D22.
- [ ] **Existing file-upload UI** — pending [[doc-processing]] Q14 verification; entry-point per [[doc-processing]] D23.

### Dependencies
- [[document-processing]] T-571 V1 prototype landed end-to-end.
- [[document-processing]] D22 substrate prompt extended with per-transaction `recurring` field per [[D21]] (cross-project task).
- BrainDrive's "Finance project page" must exist as a usable surface ([[Q6]] — likely a braindrive-repo question, resolved by Dave J's prototype).

### Constraints
- **Privacy/security:** No third-party transaction aggregator. Files stay on owner's instance ([[D4]] pillar #3, [[doc-processing]] D13/D14).
- **Cost:** Per-parse cost is governed by [[doc-processing]] D24 / [[D11]] (cover-cost-only). Each Q&A call is a Haiku invocation; volume is low (owner asks a few times a month).
- **Latency:** Report regeneration after upload is async; conversational Q&A is interactive — must feel responsive. Cache the latest report; only regenerate on state change.
- **Compatibility:** BrainDrive React chat-only client (current). Reports must render in BrainDrive's existing file viewer (markdown definitely; HTML conditional on Q7).

### Landscape findings incorporated
- Data-ownership pillar elevated ([[D4]]) — landscape §5.3.3.
- Drill-down in V1 ([[D16]] amended) — landscape §5.1 #2.
- Subscription detection in V1 ([[D21]]) — landscape §6.1 A1.
- Paradigm-naming in spec (this document, §Overview + scope-excluded worldview accommodation) — landscape §5.2.
- V1.1 priority list — landscape §6.2.
- Explicit "do not build" list — landscape §6.3.

---

## Test Strategy

### Test Levels Required
- [x] **Unit** — Categorization rule matching (rules.md row → transaction), date-range filtering, sum aggregation, budget.md parser.
- [x] **Integration** — End-to-end on substrate output: parsed statement file → categorized → aggregated → report file written.
- [x] **Property-based** — Sum-per-category invariant ([[D18]]). Synthesized statement + budget pairs; assert `report.spent[X] == sum(transactions classified to X within month)` for all inputs.
- [x] **E2E** — Dave W's BoA + Capital One May 2026 statements → real-world dogfood. Manual hand-verification against bank web totals.

### Verification Approach
- **Agent self-verification:** Property test suite for the sum invariant; integration suite that runs a fixture statement through the full pipeline and asserts the generated report matches a golden file. Failed property = failed CI.
- **Human verification (Dave W):** Upload May statements, ask "how am I doing?" — confirm (a) numbers match hand-computation against the bank's online portal, (b) the answer feels trustworthy without re-checking. [[D15]] success criterion.
- **Production monitoring:** No production monitoring needed for V1 dogfood (single owner, single machine). V1.1 may add a Sum-Invariant Watchdog that surfaces in chat when violated.

### Baseline Impact
- **Always-run checks affected:** BrainDrive's existing test suite; new tests added for budgeting categorization + report generation + invariant.
- **Additional checks triggered:** Property-based tests for [[D18]] invariant. Cross-project: [[document-processing]] substrate prompt change for [[D21]] must not break existing substrate property tests (substrate D17 sum-to-total still passes).
- **Global properties affected:** None outside the Finance project page surface. Doesn't touch auth, doesn't touch other project pages, doesn't touch BrainDrive Model routing (uses it; doesn't modify it).

---

## Security Considerations

### Risk Level
- [x] **Low** — No new authentication, no new credentials, no new external network surface, no new third-party APIs. All data is owner's own financial data, stored in owner's BrainDrive memory ([[D4]] pillar #3).

### Threat Assessment
- **User input:** Budget.md edits (text), conversational corrections (text), statement uploads (substrate handles validation). No injection vectors beyond substrate's existing concerns.
- **Code execution:** None. Budgeting layer doesn't run user-provided code.
- **Data sensitivity:** Financial data — high sensitivity. Mitigation: stays on owner's BrainDrive instance ([[doc-processing]] D13/D14). No third-party sharing.
- **Network surface:** None new. Substrate handles the Haiku API call ([[doc-processing]] D22); budgeting consumer uses BrainDrive Model's existing routing.
- **Blast radius:** Limited to the owner's BrainDrive instance. If their device is compromised, financial files are visible — but that's not a budgeting-feature concern (same risk as any memory file).

### Required Mitigations
- [x] Substrate's existing privacy guarantees ([[doc-processing]] D14: transit-only on Concierge infra) inherited unchanged.
- [x] Reports never include credentials or PII beyond transaction details that already exist in source statements.
- [x] Rules.md never stores credentials or auth tokens — it's category mappings only.

### Notes
N/A — risk profile is "same as any other memory file in the owner's BrainDrive."

---

## Explicit Boundaries

> **For AI Agents:** These boundaries define what is OUT OF SCOPE for this feature. Do not modify, touch, or refactor anything in these areas.

### Do Not Modify
- [ ] **BrainDrive Model routing** — substrate concern; budgeting consumer USES the existing routing, does not extend or alter it.
- [ ] **Haiku parsing prompt** — only the additive `recurring` field per [[D21]] is in scope, and that change is owned by the [[document-processing]] substrate, not this project. Cross-project task.
- [ ] **Substrate output file format** (per [[document-processing]] D26/D16/D12) — budgeting consumes; doesn't reshape.
- [ ] **Other project pages in BrainDrive** (Health, Transcripts, etc.) — Finance only.
- [ ] **Authentication, authorization, user identity** — not in scope.

### Do Not Introduce
- [ ] **Plaid SDK, Finicity SDK, MX SDK, or any bank-aggregator library** — anti-differentiator ([[D4]] pillar #3).
- [ ] **Separate database** — markdown files are the storage layer.
- [ ] **Separate billing surface** — cost falls out of BrainDrive Model credit usage per [[doc-processing]] D24.
- [ ] **Plugin architecture for budgeting** — this is core, not a plugin.
- [ ] **Zero-based / envelope budgeting models** — V1 is category-tracking only ([[D6]], spec §Overview).
- [ ] **A new conversational personality** — uses BrainDrive's existing advisor voice ([[D4]] pillar #1, braindrive-repo D182).

### Security Boundaries
- [ ] Never commit secrets or credentials in any markdown file (budget.md, rules.md, statements/*, reports/*).
- [ ] Never modify auth/authorization without explicit approval — not in scope.
- [ ] Reports never include account numbers, routing numbers, or full PANs (substrate strips these per substrate prompt; budgeting consumer is downstream).

### Out of Scope (Even if Related)
- [ ] **Refactoring the Finance project page itself** — beyond what's required for the budgeting feature handlers.
- [ ] **Refactoring [[document-processing]] substrate beyond the [[D21]] recurring-field extension** — cross-project scope; substrate maintainer owns.
- [ ] **General-purpose advisor improvements** — BrainDrive personality work happens elsewhere.
- [ ] **Replace the chat UI** — out of scope.
- [ ] **HTML rendering capability in BrainDrive** — Q7's outcome is consumed but not built by this project; cross-project to braindrive-repo / Dave J.

---

## Open Questions

- [ ] **Q7** — Can BrainDrive render HTML report templates in V1? Dave J investigates as part of V1 build. Markdown is the guaranteed fallback ([[D5]]).
- [ ] **Q11** — Dedup detection mechanism (likely Haiku-extracted source + date metadata, but TBD during V1 build). Owner: Dave J.
- [ ] **Q12** — Finance project interview design and ownership (cross-project to braindrive-repo). **Required for US-1 interview-driven trigger to fire automatically.** Fallback if not built: V1 budget setup triggers only on explicit owner ask. Owner: Dave J + Dave W.
- [ ] **Q9** — Is "this month" calendar month or owner-configurable (paycheck cycle)? V1 default: calendar month; revisit if Dave W's dogfood reveals friction.
- [ ] **Q10** — *(Resolved by [[D22]])* — `type` field on every transaction (`expense | income | transfer | refund | fee`), classified at Haiku parse time. Substrate-side change; consumed by budgeting filter logic.
- [ ] **Q-L6** — Worldview-bound users (YNAB/zero-based die-hards): explicitly out of V1 scope (this spec). Confirm in V1 marketing language that this is a deliberate audience cut.
- [ ] **Q-L7** — Net worth timing (V1.1 priority? or V2?). Not a V1 spec blocker.

---

## Success Definition

When this feature is V1-complete, **Dave W will be able to:**

1. Walk through conversational setup on a new Finance project page, define his categories, and store his budget — without leaving chat.
2. Upload his BoA + Capital One statements through the existing BrainDrive upload UI (per [[doc-processing]] D23 / Q14).
3. See a proactive summary in chat after each upload, including suspected subscriptions ([[D21]]).
4. Ask *"how am I doing this month?"* and get a conversational summary plus a link to the breakdown report — with numbers that match hand-computation against his bank's online portal ([[D15]]).
5. Drill into any category conversationally and see the full transaction list (amended [[D16]]).
6. Correct a miscategorization in chat and have BrainDrive offer to learn the pattern via `finance/rules.md` ([[D11]], [[D17]]).
7. Open `finance/reports/latest.md` and see his per-category budget vs. actual at a glance ([[D5]], [[D16]]).
8. Edit `finance/budget.md` directly when his targets change, with BrainDrive picking up the new limits on next report refresh.
9. Trust the answer enough that he doesn't fall back to another app for the dogfood month ([[D15]]).

V1 is **specifically not done** until both halves of [[D15]] hold: (a) numerical correctness AND (b) Dave W's subjective trust that he doesn't feel the need to double-check the numbers elsewhere.

---

## Changelog

| Date | Change | Reason | Source | Decision |
|------|--------|--------|--------|----------|
| 2026-05-13 | Initial spec | `/feature-spec` after `/interview` + `/landscape` | This session | D1–D21 |
| 2026-05-13 | Scope clarified to include credit card statements; transfer classification at parse time; Q10 resolved | Spec review: Dave W observed bank-only framing was incomplete; credit card payments create the transfer-symmetry concern | This session | D22 |
| 2026-05-13 | US-1 trigger amended: not auto-on-Finance-page-entry, but interview-driven OR explicit owner ask | Spec review: Dave W observed Finance project interview is the correct gateway, not budgeting auto-creation | This session | D8 amended; Q12 opened |

## Conversation References

| Date | Source | Topics Discussed | Link |
|------|--------|-----------------|------|
| 2026-05-13 | `/interview` (Claude + Dave W) | All 7 rounds covering frame, persona, architecture, behavior, scope, invariants, security | This conversation |
| 2026-05-13 | `/landscape` (research agent) | Competitive feature landscape across 10+ consumer apps; 4 V1 tweaks | [[landscape.md]] |
| 2026-05-13 | Project scaffolding (Dave W + Claude) | Project split from [[document-processing]] | [[decisions.md]] D1 |

---

## Approval

- [ ] Reviewed by: _______________
- [ ] Date: _______________
- [ ] Ready for Planning: [ ]

---

*Next: Generate `build-plan.md` using the `/plan` skill.*
