Status: implemented schema v2
Last reviewed: 2026-08-21
SQLiteRunRepository is the local system of record for run coordination and
audit provenance. The schema is deliberately compact: strongly typed domain
artifacts remain canonical JSON, while columns needed for identity, lineage,
integrity, and operational queries are normalized.
erDiagram
RUNS ||--o{ ATTEMPTS : contains
RUNS ||--o{ GOALS : evaluates
RUNS ||--o{ QUERIES : executes
ATTEMPTS ||--o{ QUERIES : emits
QUERIES ||--o{ HITS : discovers
HITS ||--o{ CAPTURES : captured_as
RUNS ||--o{ ARTIFACTS : produces
ATTEMPTS o|--o{ ARTIFACTS : may_produce
RUNS ||--o{ APPROVALS : governs
ARTIFACTS ||--o{ APPROVALS : reviewed_as
RUNS {
text run_id PK
text status
text request_json
text created_at
text updated_at
}
ATTEMPTS {
text attempt_id PK
text run_id FK
integer attempt_number UK
text status
text started_at
text completed_at
text goal_report_json
}
GOALS {
text goal_id PK
text run_id FK
text criterion_key UK
text description
integer required
text status
real score
text evidence_json
text created_at
text updated_at
}
QUERIES {
text execution_id PK
text run_id FK
text attempt_id FK
text query_id
text force
text query_text
text rationale
text preferred_source_classes_json
text recency
text provider
text executed_at
text query_sha256
}
HITS {
text source_id PK
text execution_id FK
text query_id
integer rank UK
text title
text url UK
text snippet
text provider
text retrieved_at
text search_hit_sha256
}
CAPTURES {
text capture_id PK
text source_id FK
text execution_id
text query_id
text discovered_url
text final_url
text title
text publisher
text retrieved_at
text media_type
integer byte_length
text content_sha256
text extracted_text_sha256
text extracted_text
integer text_truncated
text trust_classification
}
ARTIFACTS {
text artifact_id PK
text run_id FK
text attempt_id FK
text artifact_type
integer schema_version
text content_sha256
text payload_json
text created_at
}
APPROVALS {
text approval_id PK
text run_id FK
text artifact_id FK
text role
text reviewer
text reviewed_at
text decision
text brief_sha256
text approval_json
}
SCHEMA_MIGRATIONS is omitted from the diagram because it has no domain
relationship. It records version, name, and applied_at; SQLite
user_version mirrors the latest applied migration.
| Relationship | Cardinality and rule |
|---|---|
| Run to attempt | Attempt 1 is the durable acquisition phase; completed Ralph attempts follow from number 2. (run_id, attempt_number) and (run_id, attempt_id) are unique. |
| Run to goal | A run has one row per criterion key; goal status is an updatable projection of evaluation history. |
| Attempt to query | Every executed query belongs to an existing attempt in the same run through a composite foreign key. |
| Query to hit | Hits are ordered by rank; rank and canonical URL are unique within one execution. |
| Hit to capture | Every capture starts from a registered hit. Multiple time-separated captures are representable, although capture IDs are content-derived. |
| Run/attempt to artifact | An artifact always belongs to a run and may be associated with one attempt in that same run. |
| Artifact to approval | Every approval names an immutable artifact and must carry its exact content SHA-256. |
All foreign-key deletes use RESTRICT. Provenance cannot be erased by deleting a
parent through ordinary repository operations.
flowchart LR
MUTABLE[Mutable coordination projections]
APPEND[Append-only audit records]
MUTABLE --> R[RUNS status and updated_at]
MUTABLE --> A[ATTEMPTS completion status and report]
MUTABLE --> G[GOALS status, score, and evidence]
APPEND --> Q[QUERIES]
APPEND --> H[HITS]
APPEND --> C[CAPTURES]
APPEND --> T[ARTIFACTS]
APPEND --> P[APPROVALS]
Schema v2 installs BEFORE UPDATE and BEFORE DELETE triggers for queries,
hits, captures, artifacts, and approvals. The repository inserts these records
inside bounded transactions. Attempts and goals are intentionally mutable
coordination rows. Each completed Ralph attempt is also serialized as a
hash-verified ralph_checkpoint artifact before a retry can start; the final
analysis result and local audit sidecar retain the complete Ralph history.
Human review does not update an attempt artifact. Each accepted decision appends
an approval_quality_report, a board_memo_markdown revision, and an
analysis_result_revision. The latter contains the current
HumanApprovalProjection, including the immutable attempt-time approval outcome
and the post-review outcome. The GOALS row is a current query projection; the
append-only artifacts and approvals are the audit history.
| Record | Integrity mechanism |
|---|---|
| Query | SHA-256 of the canonical ResearchQuery: ID, force, text, rationale, preferred source classes, and recency. Provider and execution time are stored immutably but are not part of this hash. |
| Search hit | SHA-256 of execution identity, rank, canonical URL, metadata, provider, and retrieval time |
| Capture | Registered source_id match; discovered URL match; raw-content and extracted-text SHA-256 hashes |
| Artifact | SHA-256 of canonical JSON payload; recomputed on read |
| Approval | Foreign key to artifact plus brief_sha256 == artifact.content_sha256 check in repository service |
The database hashes are tamper-evidence within the local application boundary, not cryptographic signatures or remote attestation. A workstation administrator can replace the database and application together; stronger non-repudiation would require signed manifests and external immutable storage.
On open, the repository applies:
PRAGMA foreign_keys = ON;PRAGMA journal_mode = WAL;PRAGMA synchronous = NORMAL;PRAGMA busy_timeout = 5000;- numbered, transactional migrations;
PRAGMA optimizeduring explicit optimization and clean close.
A writable AnalysisService additionally owns a process-local registration and
POSIX advisory lock on <database>.writer.lock; this sidecar is coordination
state, not an ERD entity. Read-only inspection opens the existing database using
SQLite mode=ro plus query_only and does not acquire the writer lease.
:memory: is supported for tests. All other paths are resolved as local
filesystem paths; SQLite URI syntax and network-like URLs are rejected.
Schema v2 creates operational indexes for:
- run status and latest update;
- attempt number by run;
- required goal status by run;
- query execution time by attempt;
- hit rank by query and URL lookup;
- captures by source and retrieval time;
- artifacts by run, type, and creation time;
- approvals by artifact, role, and decision.
The normalized schema does not duplicate every Pydantic field. Canonical request,
goal evidence, attempt report, artifact, and approval payloads are stored as
validated JSON with json_valid checks. The application must deserialize them
back through their Pydantic contracts before using them at a gate. SQLite JSON
validity alone is not domain validation.
CAPTURES.extracted_text is deliberately retained for evidence review. It is
untrusted public content and must never be executed, interpreted as HTML in the
UI, or included in outbound queries without a new egress review.
The evidence snapshot is represented by a deterministic hash of the ordered
promoted EvidenceItem set inside Ralph state and result artifacts; schema v2
does not have a separate snapshot table. Finance calculations are likewise
stored in the Ralph/result artifact payloads rather than normalized economics
tables.
WAL databases must be backed up with the SQLite backup API or the sqlite3
.backup command while the service is stopped or quiescent. Copying only the
main database file while a WAL is active can omit committed pages. Artifacts
written outside SQLite must be backed up with the database and correlated by
run and content hash.
On API startup, after exclusive writer ownership is established, every run still
in created, acquiring_evidence, or verifying is changed to failed, open
attempts are closed as interrupted, and a failure artifact is appended. The
scan is not capped by the UI/list pagination limit. The persisted Ralph
checkpoint supports diagnosis and audit; it is not a resumable execution
checkpoint in this release.
SQLite, its WAL sidecars, and rendered run artifacts are ordinary local plaintext files. Content hashes detect accidental or unauthorized payload changes within the application boundary; they do not encrypt the content.