Document reference database read contract
This commit is contained in:
159
docs/reference-database-read-contract.md
Normal file
159
docs/reference-database-read-contract.md
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
# Read contract for the WCX reference database
|
||||||
|
|
||||||
|
## Purpose and ownership
|
||||||
|
|
||||||
|
This document defines the current SQLite read contract used by
|
||||||
|
`scripts/match_filenames.py` when matching local video filenames against the
|
||||||
|
WCX reference database. The contract identifies the database objects that the
|
||||||
|
file-management code depends on and the compatibility boundary that the
|
||||||
|
reference-data project must preserve.
|
||||||
|
|
||||||
|
The reference-data project owns the database schema, canonical metadata,
|
||||||
|
history, and aliases. It is the sole writer to the reference database.
|
||||||
|
File-management code is a consumer only and must open the database through a
|
||||||
|
SQLite URI with `mode=ro` and `uri=True`.
|
||||||
|
|
||||||
|
Local file paths, local processing state, matching decisions, and collection
|
||||||
|
state are outside this contract and must not be written to the reference
|
||||||
|
database.
|
||||||
|
|
||||||
|
## Connection contract
|
||||||
|
|
||||||
|
`scripts/match_filenames.py` resolves the configured database path, converts
|
||||||
|
it to a file URI, appends `?mode=ro`, and opens it as follows:
|
||||||
|
|
||||||
|
```python
|
||||||
|
database_uri = f"{database_file.resolve().as_uri()}?mode=ro"
|
||||||
|
|
||||||
|
with sqlite3.connect(database_uri, uri=True) as connection:
|
||||||
|
connection.row_factory = sqlite3.Row
|
||||||
|
```
|
||||||
|
|
||||||
|
The database file must already exist. The consumer must not fall back to a
|
||||||
|
normal writable SQLite connection.
|
||||||
|
|
||||||
|
## Tables and columns read
|
||||||
|
|
||||||
|
The current contract contains exactly three tables and ten selected columns:
|
||||||
|
|
||||||
|
| Table | Columns read |
|
||||||
|
| --- | --- |
|
||||||
|
| `movie` | `id`, `name`, `duration_seconds` |
|
||||||
|
| `movie_name_alias` | `movie_id`, `alias`, `normalized_alias`, `source` |
|
||||||
|
| `movie_history` | `movie_id`, `duration_seconds`, `archived_at` |
|
||||||
|
|
||||||
|
No other table or column is read by `load_movies()`.
|
||||||
|
|
||||||
|
### Column meanings for matching
|
||||||
|
|
||||||
|
| Column | Meaning in the file matcher |
|
||||||
|
| --- | --- |
|
||||||
|
| `movie.id` | Stable external identity for a movie. It links the current movie to aliases and historical durations and is the identifier that file-management data may reference externally. |
|
||||||
|
| `movie.name` | Current canonical display name and the primary name used to generate filename candidates. Empty names are excluded. |
|
||||||
|
| `movie.duration_seconds` | Current known duration. It supplies the current duration version used to support or distinguish name matches. |
|
||||||
|
| `movie_name_alias.movie_id` | Associates an alias with `movie.id`. |
|
||||||
|
| `movie_name_alias.alias` | Human-readable alternative name used to generate additional filename candidates. Empty aliases are excluded. |
|
||||||
|
| `movie_name_alias.normalized_alias` | Stored normalized form used directly for name comparison and duplicate suppression. |
|
||||||
|
| `movie_name_alias.source` | Describes the alias source and is retained in match results so the reported match can identify how the alias was obtained. |
|
||||||
|
| `movie_history.movie_id` | Associates a historical duration with `movie.id`. |
|
||||||
|
| `movie_history.duration_seconds` | Earlier known duration. Positive values are used as historical duration versions so an older local release can still support a match. |
|
||||||
|
| `movie_history.archived_at` | Identifies when the historical version was archived and is retained with the historical duration for diagnostics and reporting. |
|
||||||
|
|
||||||
|
`movie.id` is the stable external identity in this contract. `movie.name` is
|
||||||
|
not an external identity: the site importer can update the current name and
|
||||||
|
archives the previous movie state in `movie_history`. File-management records
|
||||||
|
must therefore refer to `movie.id`, never to a name as an identifier.
|
||||||
|
|
||||||
|
## SQL queries
|
||||||
|
|
||||||
|
The current implementation executes exactly these three queries.
|
||||||
|
|
||||||
|
### Current movies
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
duration_seconds
|
||||||
|
FROM movie
|
||||||
|
WHERE name IS NOT NULL
|
||||||
|
AND TRIM(name) <> ''
|
||||||
|
ORDER BY name, id
|
||||||
|
```
|
||||||
|
|
||||||
|
### Aliases
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT
|
||||||
|
movie_id,
|
||||||
|
alias,
|
||||||
|
normalized_alias,
|
||||||
|
source
|
||||||
|
FROM movie_name_alias
|
||||||
|
WHERE alias IS NOT NULL
|
||||||
|
AND TRIM(alias) <> ''
|
||||||
|
ORDER BY movie_id, alias
|
||||||
|
```
|
||||||
|
|
||||||
|
### Historical durations
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT
|
||||||
|
movie_id,
|
||||||
|
duration_seconds,
|
||||||
|
archived_at
|
||||||
|
FROM movie_history
|
||||||
|
WHERE duration_seconds IS NOT NULL
|
||||||
|
AND duration_seconds > 0
|
||||||
|
ORDER BY movie_id, archived_at
|
||||||
|
```
|
||||||
|
|
||||||
|
These are read-only `SELECT` statements. The matcher does not issue database
|
||||||
|
writes or invoke another database-writing component.
|
||||||
|
|
||||||
|
## Backward compatibility
|
||||||
|
|
||||||
|
The following schema or semantic changes would be backward-incompatible for
|
||||||
|
the current file-management code:
|
||||||
|
|
||||||
|
- removing or renaming any of the three contracted tables,
|
||||||
|
- removing or renaming any selected column,
|
||||||
|
- changing a selected value so it can no longer be converted as currently
|
||||||
|
expected (`id`, names, alias source, and archive time to text; durations to
|
||||||
|
positive integer seconds),
|
||||||
|
- making `movie.id` unstable or reusing an ID for another movie,
|
||||||
|
- breaking the relationships from `movie_name_alias.movie_id` or
|
||||||
|
`movie_history.movie_id` to `movie.id`,
|
||||||
|
- changing `duration_seconds` to another unit or meaning,
|
||||||
|
- changing `normalized_alias` so it no longer represents the normalized alias
|
||||||
|
expected by filename comparison,
|
||||||
|
- changing the meaning of `source` such that it can no longer identify the
|
||||||
|
alias provenance shown in match output, or
|
||||||
|
- preventing the three queries from running through a SQLite `mode=ro`
|
||||||
|
connection.
|
||||||
|
|
||||||
|
Adding unrelated tables or columns is compatible. Adding rows, updating a
|
||||||
|
movie name while retaining the same `movie.id`, adding aliases, and appending
|
||||||
|
historical durations are also compatible with the current query contract.
|
||||||
|
|
||||||
|
## Process for contract changes
|
||||||
|
|
||||||
|
Before the reference-data project makes an incompatible change:
|
||||||
|
|
||||||
|
1. Identify the affected table, column, value semantics, or relationship and
|
||||||
|
document the proposed replacement.
|
||||||
|
2. Update the file-management consumer to support the new contract, preferably
|
||||||
|
with a transition period in which it can read both forms.
|
||||||
|
3. Create a disposable database containing representative current names,
|
||||||
|
aliases, current durations, and historical durations under the proposed
|
||||||
|
schema.
|
||||||
|
4. Verify all three queries and representative filename matching against that
|
||||||
|
database through `mode=ro`.
|
||||||
|
5. Verify that a write through the same connection is rejected.
|
||||||
|
6. Release or deploy the compatible file-management version before removing
|
||||||
|
the old contract from the reference database.
|
||||||
|
7. Remove the old contract only after both projects explicitly agree that no
|
||||||
|
active consumer depends on it.
|
||||||
|
|
||||||
|
The projects must coordinate any incompatible change; the reference-data
|
||||||
|
project must not silently break or reinterpret the documented read contract.
|
||||||
Reference in New Issue
Block a user