From 3d0ce55fd72a32963cb416b7e39f6affc2c44945 Mon Sep 17 00:00:00 2001 From: LeonSGP <154585401+LeonSGP43@users.noreply.github.com> Date: Thu, 27 Aug 2026 16:00:36 +0800 Subject: [PATCH] docs(cookbook): add Change Management module notebook (#991) * docs(cookbook): add Change Management module notebook Add cookbook/introduction/24_Change_Management.ipynb covering the change_management module with verified, executable examples: - ChangeLogEntry with email-validated author field - InMemoryVersionStorage save/get/list_all/exists/delete round trip - named tags (save_tag/get_tag) for release pinning - compute_checksum / verify_checksum integrity verification with tamper detection The change_management module currently has no cookbook coverage. All API calls and outputs were executed against semantica/change_management/change_log.py and version_storage.py. Signed-off-by: LeonSGP43 * docs(cookbook): clarify outputs verified against repo source, not PyPI release Signed-off-by: LeonSGP43 * docs(cookbook): execute change management notebook in Jupyter (real kernel run, stream outputs, execution counts) Signed-off-by: LeonSGP43 --------- Signed-off-by: LeonSGP43 Signed-off-by: LeonSGP43 Signed-off-by: LeonSGP43 Co-authored-by: LeonSGP43 --- .../introduction/24_Change_Management.ipynb | 299 ++++++++++++++++++ 1 file changed, 299 insertions(+) create mode 100644 cookbook/introduction/24_Change_Management.ipynb diff --git a/cookbook/introduction/24_Change_Management.ipynb b/cookbook/introduction/24_Change_Management.ipynb new file mode 100644 index 00000000..3f8d3db8 --- /dev/null +++ b/cookbook/introduction/24_Change_Management.ipynb @@ -0,0 +1,299 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "8d7096ea", + "metadata": {}, + "source": [ + "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/semantica-agi/semantica/blob/main/cookbook/introduction/24_Change_Management.ipynb)\n", + "\n", + "# Change Management — Practical Guide\n", + "\n", + "Semantica's `change_management` module provides versioning, audit trails, and data-integrity checks for knowledge graphs and ontologies:\n", + "\n", + "- **`ChangeLogEntry`** — standardized change metadata (validated timestamp/author)\n", + "- **`InMemoryVersionStorage` / `SQLiteVersionStorage`** — version snapshot storage with named tags\n", + "- **`compute_checksum` / `verify_checksum`** — SHA-256 integrity verification\n", + "\n", + "This notebook runs a complete save → tag → verify → tamper-detect cycle. All outputs are real executed results verified against the repository's `semantica/change_management/` source at the time of writing (the `pip install` cell may fetch a newer release with slightly different behavior)." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "7bdffec1", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-26T18:46:37.171333Z", + "iopub.status.busy": "2026-08-26T18:46:37.171183Z", + "iopub.status.idle": "2026-08-26T18:46:39.060860Z", + "shell.execute_reply": "2026-08-26T18:46:39.059594Z" + } + }, + "outputs": [], + "source": [ + "!pip install -q semantica" + ] + }, + { + "cell_type": "markdown", + "id": "169efee1", + "metadata": {}, + "source": [ + "## 1) A `ChangeLogEntry` records *who* changed *what*, *when*\n", + "\n", + "`author` must be a valid email — the dataclass validates on construction (`ValidationError` otherwise), which keeps audit trails clean." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "5b17acdb", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-26T18:46:39.064077Z", + "iopub.status.busy": "2026-08-26T18:46:39.063818Z", + "iopub.status.idle": "2026-08-26T18:46:39.321881Z", + "shell.execute_reply": "2026-08-26T18:46:39.321036Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "ChangeLogEntry(timestamp='2026-08-15T09:00:00Z', author='demo@example.com', description='initial version', change_id=None, related_changes=[])" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from semantica.change_management import ChangeLogEntry\n", + "\n", + "entry = ChangeLogEntry(\n", + " timestamp=\"2026-08-15T09:00:00Z\",\n", + " author=\"demo@example.com\",\n", + " description=\"initial version\",\n", + ")\n", + "entry" + ] + }, + { + "cell_type": "markdown", + "id": "53d8df5c", + "metadata": {}, + "source": [ + "## 2) Save a versioned snapshot\n", + "\n", + "A snapshot is a dict with a required `label` plus your payload. Here we attach the KG data, the change log, and a SHA-256 `checksum` computed over everything except the checksum field itself." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "fec16f24", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-26T18:46:39.325528Z", + "iopub.status.busy": "2026-08-26T18:46:39.325140Z", + "iopub.status.idle": "2026-08-26T18:46:39.331480Z", + "shell.execute_reply": "2026-08-26T18:46:39.330586Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from semantica.change_management import InMemoryVersionStorage, compute_checksum\n", + "\n", + "storage = InMemoryVersionStorage()\n", + "\n", + "snapshot = {\n", + " \"label\": \"v1.0.0\",\n", + " \"data\": {\"entities\": {\"acme\": {\"type\": \"Company\"}}},\n", + " \"change_log\": {\n", + " \"timestamp\": entry.timestamp,\n", + " \"author\": entry.author,\n", + " \"description\": entry.description,\n", + " },\n", + "}\n", + "snapshot[\"checksum\"] = compute_checksum({k: v for k, v in snapshot.items() if k != \"checksum\"})\n", + "\n", + "storage.save(snapshot)\n", + "storage.exists(\"v1.0.0\")" + ] + }, + { + "cell_type": "markdown", + "id": "0f1c603b", + "metadata": {}, + "source": [ + "## 3) Named tags pin a version for releases\n", + "\n", + "`save_tag` / `get_tag` map stable names (e.g. `release`) to version labels, decoupling consumers from label churn." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "62f7643e", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-26T18:46:39.335182Z", + "iopub.status.busy": "2026-08-26T18:46:39.334886Z", + "iopub.status.idle": "2026-08-26T18:46:39.339586Z", + "shell.execute_reply": "2026-08-26T18:46:39.338568Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "('v1.0.0', ['v1.0.0'])" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "storage.save_tag(\"release\", \"v1.0.0\")\n", + "\n", + "storage.get_tag(\"release\"), [s[\"label\"] for s in storage.list_all()]" + ] + }, + { + "cell_type": "markdown", + "id": "96df12da", + "metadata": {}, + "source": [ + "## 4) Verify integrity — and catch tampering\n", + "\n", + "`verify_checksum(snapshot)` recomputes the SHA-256 over the snapshot (minus its `checksum` field) and compares. A single mutated character in the data flips the result to `False`." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "26d0de85", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-26T18:46:39.342653Z", + "iopub.status.busy": "2026-08-26T18:46:39.342466Z", + "iopub.status.idle": "2026-08-26T18:46:39.346714Z", + "shell.execute_reply": "2026-08-26T18:46:39.345623Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "intact: True\n", + "tampered: False\n" + ] + } + ], + "source": [ + "from semantica.change_management import verify_checksum\n", + "\n", + "stored = storage.get(\"v1.0.0\")\n", + "print(\"intact:\", verify_checksum(stored))\n", + "\n", + "tampered = storage.get(\"v1.0.0\")\n", + "tampered[\"data\"][\"entities\"][\"acme\"][\"note\"] = \"mutated after the fact\"\n", + "print(\"tampered:\", verify_checksum(tampered))" + ] + }, + { + "cell_type": "markdown", + "id": "bd14c3e4", + "metadata": {}, + "source": [ + "## 5) Retiring a version\n", + "\n", + "`delete(label)` removes a snapshot; tags pointing at it are your responsibility to update." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "de9fe3e5", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-26T18:46:39.349814Z", + "iopub.status.busy": "2026-08-26T18:46:39.349513Z", + "iopub.status.idle": "2026-08-26T18:46:39.354710Z", + "shell.execute_reply": "2026-08-26T18:46:39.353669Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "storage.delete(\"v1.0.0\")\n", + "storage.exists(\"v1.0.0\")" + ] + }, + { + "cell_type": "markdown", + "id": "ab667b32", + "metadata": {}, + "source": [ + "## Summary\n", + "\n", + "| Task | API |\n", + "|---|---|\n", + "| Record audit metadata | `ChangeLogEntry(timestamp, author=email, description)` |\n", + "| Persist a version | `InMemoryVersionStorage().save({\"label\": ..., ...})` |\n", + "| Pin a release name | `save_tag(\"release\", \"v1.0.0\")` / `get_tag(\"release\")` |\n", + "| Integrity check | `compute_checksum(snap)` / `verify_checksum(snap)` |\n", + "| Persistent backend | `SQLiteVersionStorage(path)` — same interface |\n", + "\n", + "See also `semantica/change_management/change_management_usage.md` for the manager classes (`TemporalVersionManager`, `OntologyVersionManager`)." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}