- Add tools/validate.py: validates packages, and with --correction runs proposed corrections through the gate against a package without writing anything (spec/11 §11.4). The gate now refuses a proposal that fails the correction schema, rule correction.schema. - tools/load.py validates every package before loading, and with --bundle --built-from builds a scienting-bundle/1 with the FTS5 search index and bundle_meta (spec/13 §13.5). Search rows are defined per unit (sentence, cell, equation outside a sentence, figure-text) with the parent kind as context. - Roster keys carry a role, and a key with the role owner may revoke any receipt (spec/08 §8.7, spec/20); roster schema, store table and the fixture roster updated. The checker signs a trial revocation to prove the rule both ways. - A qa: receipt raises the nodes it sampled except those in its errors (spec/08 §8.2); the example paper's fidelity counts become 27 F3, 13 F2, 4 F1 and 1 F0. - The destination chooses the keyed scheme, not the text policy: hmac-team between the team's machines, hkdf-pages outside the team (spec/05 §5.8, spec/12 §12.5). - A TextQuoteSelector must repeat the anchor's plain quote and is absent for hashed or keyed anchors (spec/18 §18.3). - Add fixtures/records/suspect.json, a scienting-suspect/1 record. - Oracle: hashes are kept incrementally and checked after every correction against a full recomputation; load and write refuse unsafe manifest paths; Ed25519, HKDF and schema validation come from the cryptography and jsonschema packages; canonical JSON uses the built-in encoder with an exact RFC 8785 fallback. - The tools need Python 3.14 with cryptography and jsonschema; the py310 CI environment is dropped and the workflow runs the default only. - Resolve every [CHECK] note in the docs, READMEs and context; add CONTRIBUTING.md; every tool answers --help and refuses unknown options. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
3.9 KiB
SQL
This folder holds the table definitions for the database form of packages, a team's store, and the bundle.
What the database form is for
A package is a folder of canonical JSON files, one document per folder (chapter 12). Canonical JSON is JSON with exactly one valid byte sequence, so a file's hash changes only when its content does.
Handing over a folder is easy. Querying across hundreds of documents in folders is hard. The database form holds the same data as rows so that a team can ask SQL questions of it, and a package loaded into the tables unloads back to the same bytes. About 500 documents come to about a million and a half rows, and SQLite and Dolt hold that comfortably (chapter 13).
The three files
| File | Holds | Runs on |
|---|---|---|
doc.sql |
Documents: works, documents, witnesses, nodes, pages, locations, references, citations, corrections, IDs, receipts, revocations, suspects and package files. | SQLite, Dolt, PostgreSQL |
store.sql |
What a team adds: roster keys, projects, members, reading paths, layers, annotations, datasets, digitizations, views, policies, submissions and grades. Load doc.sql first. |
SQLite, Dolt, PostgreSQL |
bundle-sqlite.sql |
The bundle's extra tables: metadata, a full-text index (FTS5, SQLite's search extension) and room for embeddings. Load both files above first. | SQLite |
Creating a database
sqlite3 lab.db < sql/doc.sql && sqlite3 lab.db < sql/store.sql
psql -d lab -f sql/doc.sql && psql -d lab -f sql/store.sql
dolt sql < sql/doc.sql && dolt sql < sql/store.sql
The PostgreSQL database lab and the Dolt repository must already exist.
The sqlite3 line runs as shown; the psql and dolt lines follow the portability rules of chapter 13 but have not been run on those engines in this repository.
To load packages into SQLite without pixi, run python3 tools/load.py --sqlite lab.db PACKAGE… with Python 3.14 and two packages, jsonschema and cryptography installed.
The file docs/examples.md has queries to try.
The loader copies files that have no table (assets, dataset files, derived files) by SHA-256 into lab.db.assets/.
A first query
The query below finds every sentence that cites a given reference, which is the citation's context.
It returns sentence IDs, and nodes.content holds each sentence's text.
SELECT c.sentence
FROM citations c
JOIN refs r ON r.doc_key = c.doc_key AND r.node = c.ref_node
WHERE c.doc_key = 'hale2026harmonic' AND r.label = '2';
On fixtures/packages/hale2026harmonic it returns one row, f929eq9: the sentence ending "served as the first test case, with a bending band near 1595 cm⁻¹."
Conventions
- Foreign keys: none. Validators check references, so the same file runs everywhere.
- Types: enumerations are
VARCHARwith aCHECK, JSON values are canonical JSON inTEXT, and booleans areINTEGER0 or 1. - Names: no table, column or index name is reserved in SQLite, PostgreSQL or MySQL (Dolt is MySQL-compatible).
The formats'
key,index,at,by,beforeandafterbecomedoc_key,idx,made_at,signer,before_hashandafter_hash. - Round trip: each row keeps every property of its record, so unloading restores the same bytes and the same manifest hash.
Unloading copies the files with no table from the asset store, which must travel with the database.
tools/check.pytests this for every fixture package. - Derived tables:
citations,receipt_nodesandannotation_targetsare built on load for queries and are not part of the package.
Status
The version is 0.1.0.
In registry/formats.json, scienting-doc/1 is candidate, and the bundle and the project, dataset, digitization and view formats are provisional. Chapter 13 defines the mapping from files to tables.