docs(prd): add sqlite local storage plan
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
# PRD prd-new: SQLite local storage
|
||||
|
||||
- **Status:** Draft
|
||||
- **Author:** codex
|
||||
- **Created:** 2026-07-01
|
||||
- **Issue:** #319
|
||||
|
||||
## Summary
|
||||
|
||||
Add a small stdlib SQLite storage layer for bot-bottle host runtime state,
|
||||
starting with the supervise queue and audit log. This replaces scattered JSON
|
||||
queue files and JSONL audit logs with structured tables while preserving the
|
||||
existing public supervise helper functions and sidecar queue mount contract.
|
||||
|
||||
## Problem
|
||||
|
||||
Bot-bottle currently stores supervise proposals and responses as individual JSON
|
||||
files under `~/.bot-bottle/queue/<slug>/`, and audit entries as JSONL files
|
||||
under `~/.bot-bottle/audit/`. That worked for the original interactive TUI, but
|
||||
new forge-native orchestration needs durable, queryable local state for queues,
|
||||
audit trails, watchdogs, and lifecycle records. PR #318 started introducing
|
||||
SQLite-shaped boilerplate for forge state; the storage foundation should live in
|
||||
its own PR so forge work can build on the shared runtime store instead of adding
|
||||
one-off persistence.
|
||||
|
||||
## Goals / Success Criteria
|
||||
|
||||
1. Supervise proposals and responses are persisted through SQLite.
|
||||
2. Audit entries are persisted through SQLite.
|
||||
3. Existing public supervise helpers keep their current call shape where
|
||||
practical: `write_proposal`, `read_proposal`, `list_pending_proposals`,
|
||||
`write_response`, `read_response`, `wait_for_response`,
|
||||
`archive_proposal`, `write_audit_entry`, and `read_audit_entries`.
|
||||
4. The sidecar queue mount still works across docker, smolmachines, and
|
||||
macOS-container backends.
|
||||
5. The implementation stays stdlib-only.
|
||||
6. Unit tests cover queue round-trips, pending discovery, response waits,
|
||||
archive semantics, audit round-trips, and path creation.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Migrating old JSON queue files or JSONL audit logs.
|
||||
- Adding forge orchestration state tables.
|
||||
- Adding egress metering or budget tables.
|
||||
- Changing the supervise TUI workflow or remediation behavior.
|
||||
- Introducing a third-party ORM or migration framework.
|
||||
|
||||
## Design
|
||||
|
||||
### Database locations
|
||||
|
||||
Queue state remains tied to the mounted per-bottle queue directory:
|
||||
|
||||
```text
|
||||
~/.bot-bottle/queue/<slug>/supervise.db
|
||||
```
|
||||
|
||||
The supervise sidecar already receives that directory at
|
||||
`/run/supervise/queue`, so both the sidecar and host TUI can read and write the
|
||||
same SQLite file without changing backend mounts.
|
||||
|
||||
Audit state uses the host-level local database:
|
||||
|
||||
```text
|
||||
~/.bot-bottle/bot-bottle.db
|
||||
```
|
||||
|
||||
This creates the shared host database that later forge/native lifecycle work can
|
||||
extend in separate PRDs.
|
||||
|
||||
### Tables
|
||||
|
||||
`supervise_proposals` lives in the per-queue database:
|
||||
|
||||
```sql
|
||||
CREATE TABLE supervise_proposals (
|
||||
id TEXT PRIMARY KEY,
|
||||
bottle_slug TEXT NOT NULL,
|
||||
tool TEXT NOT NULL,
|
||||
proposed_file TEXT NOT NULL,
|
||||
justification TEXT NOT NULL,
|
||||
arrival_timestamp TEXT NOT NULL,
|
||||
current_file_hash TEXT NOT NULL,
|
||||
archived INTEGER NOT NULL DEFAULT 0
|
||||
);
|
||||
```
|
||||
|
||||
`supervise_responses` lives in the same per-queue database:
|
||||
|
||||
```sql
|
||||
CREATE TABLE supervise_responses (
|
||||
proposal_id TEXT PRIMARY KEY,
|
||||
status TEXT NOT NULL,
|
||||
notes TEXT NOT NULL,
|
||||
final_file TEXT,
|
||||
archived INTEGER NOT NULL DEFAULT 0
|
||||
);
|
||||
```
|
||||
|
||||
`supervise_audit_entries` lives in the host database:
|
||||
|
||||
```sql
|
||||
CREATE TABLE supervise_audit_entries (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
timestamp TEXT NOT NULL,
|
||||
bottle_slug TEXT NOT NULL,
|
||||
component TEXT NOT NULL,
|
||||
operator_action TEXT NOT NULL,
|
||||
operator_notes TEXT NOT NULL,
|
||||
justification TEXT NOT NULL,
|
||||
diff TEXT NOT NULL
|
||||
);
|
||||
```
|
||||
|
||||
### Compatibility
|
||||
|
||||
The existing helper functions keep accepting `Path` arguments for queue
|
||||
directories. Internally, they map the queue directory to `supervise.db` and
|
||||
perform equivalent operations:
|
||||
|
||||
- `list_pending_proposals` returns non-archived proposals without a non-archived
|
||||
response, sorted by arrival time.
|
||||
- `archive_proposal` marks matching proposal/response rows archived instead of
|
||||
moving files into `processed/`.
|
||||
- `wait_for_response` keeps the current polling behavior but polls SQLite.
|
||||
|
||||
The old path helpers (`queue_dir_for_slug`, `audit_dir`, `audit_log_path`) stay
|
||||
available for compatibility. `audit_log_path` no longer describes the active
|
||||
storage location; callers should use `read_audit_entries`.
|
||||
|
||||
## Implementation chunks
|
||||
|
||||
1. Add SQLite store helpers for supervise queue and audit state.
|
||||
2. Rewire `bot_bottle.supervise` queue/audit functions to the store.
|
||||
3. Update supervise CLI discovery tests and queue/audit unit tests.
|
||||
4. Run unit tests, pyright, and pylint for touched modules.
|
||||
|
||||
## Open questions
|
||||
|
||||
None.
|
||||
Reference in New Issue
Block a user