From 2c0505b3cd1b01092b0014906994ed53b7d1691b Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 30 May 2026 23:25:34 +0000 Subject: [PATCH] docs(adr): supersede ADR-0011 with ADR-0012 (json-family implemented, V-L2-F3) Reconcile the decision record with main. V-L2-F3 (#146, shipped in #148) deliberately reversed the V-L2-F2 json *drop* and implemented a JSON-family sidecar backend (plain / JSON-LD / NDJSON) with full SQLite-parity octad runtime and a real storage abstraction (sidecar::StorageKind + a format-independent SidecarData codec). That landed on main just before the V-L2-F2 wrap-up docs (#149), leaving ADR-0011, the CHANGELOG, and the README contradicting the code. - docs(adr): add ADR-0012 documenting the V-L2-F3 reversal + implementation; mark ADR-0011 "Superseded by ADR-0012" (retained as the historical record of the F2 decision, which did ship in #144). - docs(changelog): replace the intra-cycle "Removed: drop json" entry with an "Added: JSON-family sidecar backend" entry reflecting the net state. - docs(readme): the legacy [tier1.provenance] example now lists "sqlite | postgres | json". Docs only; no code change. fmt/clippy/test (142) green on main. https://claude.ai/code/session_01Ux144vBDdySvLUqUrCgkT4 --- CHANGELOG.md | 5 +- README.adoc | 2 +- .../0011-sidecar-storage-is-relational.adoc | 17 +++- .../0012-json-family-sidecar-storage.adoc | 87 +++++++++++++++++++ 4 files changed, 102 insertions(+), 9 deletions(-) create mode 100644 docs/decisions/0012-json-family-sidecar-storage.adoc diff --git a/CHANGELOG.md b/CHANGELOG.md index 849767d..b59e27f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ this project aims to follow [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- feat(sidecar): JSON-family sidecar storage backend — plain JSON / JSON-LD / NDJSON with SQLite-parity octad runtime (provenance incl. forks, temporal, drift, gc); new `[sidecar].format` key and a single `StorageKind::resolve` backend resolver (V-L2-F3, ADR-0012, closes #146) (#148) - feat(codegen): split sidecar DDL by dialect; reject json sidecar (#45) (#133) - feat(codegen): split sidecar DDL by dialect; reject json sidecar (#45) (#131) - feat(logging): tracing diagnostics with --log-format/--log-level (#51) (#124) @@ -31,10 +32,6 @@ this project aims to follow [Semantic Versioning](https://semver.org/spec/v2.0.0 - feat(codegen): split sidecar DDL by dialect; reject json sidecar (#45) (#113) - feat(provenance): fork-first-class chain model — ADR-0010 (#31; supersedes #32) (#109) -### Removed - -- feat(manifest): drop the never-implemented `json` sidecar store; close `[sidecar].storage` to sqlite + postgres and reject unknown values at validate/doctor/generate (V-L2-F2, ADR-0011, closes #112) (#144, #147) - ### Fixed - fix(rhodibot): automated RSR compliance fixes (#135) diff --git a/README.adoc b/README.adoc index 0c152fb..1afeb3f 100644 --- a/README.adoc +++ b/README.adoc @@ -239,7 +239,7 @@ temporal-versioning = true # automatic version history drift-detection = true # cross-modal observer (Constraints symptom) [tier1.provenance] -sidecar = "sqlite" # sqlite | postgres (V-L2-F2 / ADR-0011) +sidecar = "sqlite" # sqlite | postgres | json (V-L2-F3 / ADR-0012) sidecar-path = ".verisimiser/provenance.db" [tier1.temporal] diff --git a/docs/decisions/0011-sidecar-storage-is-relational.adoc b/docs/decisions/0011-sidecar-storage-is-relational.adoc index 9e25583..548455b 100644 --- a/docs/decisions/0011-sidecar-storage-is-relational.adoc +++ b/docs/decisions/0011-sidecar-storage-is-relational.adoc @@ -8,10 +8,19 @@ Date: 2026-05-30 ## Status -Accepted (2026-05-30) — implemented in #144 (json dropped from the storage -enum, docs, template, and validate/doctor messaging) with test coverage in -#147. Closes #112 (V-L2-F2). Builds on #45 (V-L2-F1, the per-dialect DDL -split) and ADR-0004 (octad ontology). +**Superseded by [ADR-0012](0012-json-family-sidecar-storage.adoc) +(V-L2-F3, #146 / #148).** + +Originally Accepted (2026-05-30) and shipped as the V-L2-F2 drop — #144, +test coverage in #147, closing #112. It was then reversed *within the same +development cycle* by V-L2-F3 (#146), which re-opened and **implemented** the +JSON sidecar capability as a deliberately-scoped family (plain / JSON-LD / +NDJSON) at the maintainer's request. The "no storage-abstraction layer / +relational-only" premise below no longer holds: #148 introduced +`sidecar::StorageKind` and a format-independent `SidecarData` codec. This ADR +is retained as the historical record of the F2 decision; see ADR-0012 for the +current state. Builds on #45 (V-L2-F1, the per-dialect DDL split) and +ADR-0004 (octad ontology). ## Context diff --git a/docs/decisions/0012-json-family-sidecar-storage.adoc b/docs/decisions/0012-json-family-sidecar-storage.adoc new file mode 100644 index 0000000..5e69816 --- /dev/null +++ b/docs/decisions/0012-json-family-sidecar-storage.adoc @@ -0,0 +1,87 @@ += Architecture Decision Record: 0012-json-family-sidecar-storage + + + +# 12. Implement the JSON-family sidecar store (supersedes ADR-0011) + +Date: 2026-05-31 + +## Status + +Accepted (2026-05-31) — implemented in #148. Closes #146 (V-L2-F3). +**Supersedes [ADR-0011](0011-sidecar-storage-is-relational.adoc)** (V-L2-F2, +the json *drop*), reversing it at the maintainer's request. + +## Context + +ADR-0011 (V-L2-F2, shipped in #144) dropped the never-implemented `json` +sidecar store on the grounds that the octad runtime is relational and no +storage-abstraction layer existed to host a second backend. That reasoning +was sound *at the time*, but it rested on an absence (no abstraction) rather +than an impossibility. + +The maintainer subsequently asked for a real JSON sidecar capability (#146, +V-L2-F3) — deliberately reversing the drop — scoped as a *family* of on-disk +encodings with **full parity** to the runtime operations the SQLite path +implements today. + +## Decision + +Accept `[sidecar].storage = "json"` again, backed by a real implementation +(#148): + +* **`[sidecar].format`** selects the on-disk encoding — `plain` (default) | + `ld` (JSON-LD) | `ndjson`. It is meaningful only for `json` and ignored + for `sqlite`/`postgres`. +* **One resolver.** `sidecar::StorageKind::resolve(storage, format)` is the + single source of truth (`Sqlite | Postgres | Json(JsonFormat)`); + `SqlDialect::from_storage` is folded into it, and `validate`/`doctor`, + `generate`, `drift`, and `gc` all dispatch on it. +* **Storage abstraction.** A single `SidecarData` model mirrors the + `verisimdb_*` tables (provenance log + chain-head set, temporal versions, + lineage edges, access policies). **Format is purely a codec** over that + model — every octad operation is written once and is format-independent + (plain = table→rows object; ld = `@context` + typed `@graph`; ndjson = + one record per line). Writes are crash-safe (temp file + atomic rename). +* **Octad parity.** Provenance (`append`, `append_fork`, `verify_chain`, + `fork_points`) reuses `abi::ProvenanceEntry::compute_hash`, so hashing is + identical across backends; temporal enforces monotonic versions and the + exactly-one-current invariant in code; drift reuses the `tier1` temporal + kernel; `gc` purges by age; `generate` emits a + `sidecar_schema.{json,jsonld,ndjson}` scaffold instead of SQL DDL. + +### Relationship to ADR-0011 + +ADR-0011's premise — *no abstraction; a JSON store would re-encode +relational invariants in application code with weaker guarantees* — is +answered rather than simply contradicted: #148 introduces the abstraction +(`StorageKind` + the `SidecarData` codec) and re-encodes those invariants in +Rust with documented parity. The one acknowledged difference is concurrency: +the JSON store is single-writer (atomic whole-file rewrite) where SQLite +serialises via `BEGIN IMMEDIATE` locks. The guarantees SQL enforced +structurally (one current temporal row, monotonic versions, fork-aware +chains, hash identity) are now enforced in code for the json path and +covered by tests mirroring the SQLite suite, across all three formats. + +## Consequences + +### Positive + +- `json` / `jsonld` / `ndjson` sidecars with octad parity — human-diffable, + portable, dependency-light stores, plus a genuine linked-data (JSON-LD) + option. +- A single backend resolver (`StorageKind::resolve`) for every storage value. + +### Negative + +- The json path enforces invariants in application code rather than via SQL + constraints, so it carries a heavier test burden and a documented + single-writer limitation. +- Two storage families to maintain in lockstep (the hash function is shared + via `abi`, which mitigates the highest-risk drift). + +## References + +- Issue #146 (V-L2-F3); PR #148. +- Supersedes ADR-0011 (V-L2-F2; issue #112, shipped in #144/#147). +- ADR-0004 (octad ontology), ADR-0010 (provenance forks are first-class).