Repository navigation
AI write access: opt-in write tools with a 30-day recycle bin (ADR-0008) - #43
Merged
Merged
Conversation
Four sensitive write scopes (transactions, recurring, planning, holdings) and twelve typed single-record write tools that reuse the app's own commands and validators. Separate hourly write budget, idempotency keys, ai:<client> audit actor, before/after audit summaries, broker/investment/estimate/archived refusals, and a 30-day recycle bin for AI deletes with a purge job. Architecture tests replace 'no write tools' with an explicit allow-list.
…nts, shows writes in the audit log and a recycle bin with one-click restore EN and PT-PT strings; scope-selection helpers with specs; the E2E journey grants a writer client, creates and deletes a transaction over MCP and restores it from the recycle bin. The read-only client's tool list is unchanged.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
AI clients (MCP and the in-app assistant) can now write, opt-in per client, through the same policy gateway (ADR-0008, superseding the read-only part of ADR-0006).
Existing clients get no write access until the owner enables it. Write scopes are new, sensitive and never pre-selected; the in-app assistant's default scopes stay read-only; read-only clients get exactly the same answers as before (ids needed for writing appear only with the matching write scope).
New tools → scopes
transactions.writecreate_transaction,update_transaction,delete_transactionrecurring.writeconfirm_expected,skip_expected,upsert_recurringplanning.writeset_budget_limit,upsert_goal,add_to_goalholdings.writeupdate_crypto_holding,add_crypto_reward,update_asset_valueMCP annotations:
readOnlyHint: falseon every write tool,destructiveHint: trueondelete_transactionandskip_expected,idempotentHintper tool (false for create/upsert/add).Safeguards
yyyy-MM-dddates, existing ids, active category keys, text ≤ 120/80 chars with control/zero-width/bidi characters refused, unknown arguments refused). No bulk tools; delete takes one id.TransactionCommands,RecurringCommands,BudgetEndpoints.SaveAsync,GoalEndpoints,ManualHoldingService,InvestmentEndpoints.ValueAssetAsync): same domain rules, same ledger audit interceptor, same interest recalculation. Endpoints were refactored to call the same code.Ai:WritesPerHour, editable per client up to 200), on top of the per-minute limit.idempotency_key: a retry replays the first result (replayed: true); the same key with different arguments → 409. Receipts kept 24 h.ai:<client name>; the AI audit log marks writes and stores the record id plus a before/after summary (no secrets).untrusted_text; only write when the user explicitly asked in this conversation; summarise intended changes before writing.WriteTools;WriteToolshas no dependency on broker positions/trades/dividends/cash/snapshots/sync/integrations; no SQL/shell/file/trading/bulk tools; MCP names, argument names and annotations mirror the catalogue; the tool → scope list is pinned.Also fixes a latent bug found on the way: replacing the items of an existing budget version failed with a concurrency error because new
BudgetItems were treated as existing rows (keys are nowValueGeneratedNever, as for crypto rewards; snapshot-only migration).UI
AI access: scopes grouped Leitura / Escrita with Selecionar toda a leitura / Selecionar toda a escrita; write scopes flagged in red and confirmed before they are granted; writes-per-hour field; clients that can write are badged; audit log shows writes distinctly with their changes and a Restore link for deletions still in the bin; new Reciclagem / Recycle bin section. EN + PT-PT strings.
Test plan
dotnet build(warnings as errors)list_toolsshowing write tools only with write scopes (+ annotations) and a write over MCPng build,ng test --watch=false(77 tests, incl. new scope-selection specs)Migrations
ai:clients.writes_per_hour(default 20),audit_events.write/record_id/changes, newrecycle_binandwrite_receiptstables.finance: snapshot-only (budget item keys assigned in the domain).